Skip to content

Fix(picker,#19309): le gel s'applique a toutes les classes -- une EPIC gelee n'est plus servie - #24864

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/19309-umbrella-freeze
Nov 6, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/19309-umbrella-freeze

Conversation

@jsboige

@jsboige jsboige commented Nov 5, 2026

Copy link
Copy Markdown
Owner

Grain: MED/tooling -- lane myia-ai-01:CoursIA-2 -- prev: MED/notebook-dotnet #24859

Le defaut

Le gel d'une issue est une decision explicite du coordinateur. Deux regles le portent :

  • regle A — la ligne [FROZEN] <motif> -- <autorite> dans le corps de l'issue ;
  • regle B — un en-tete [FROZEN] dans le fil (le filet des gels deja poses en commentaire, en attendant leur migration vers le corps).

_issue_is_frozen(issue_body, comments) lisait deja les deux. Mais elle n'etait cablee que derriere has_recent_delivery_marker, lui-meme cable sur l'urne grain seule :

# scripts/pick_idle_grain.py -- draw_unclaimed
if cls == "grain" and not include_delivered:
    recent = has_recent_delivery_marker(c["number"])

Une EPIC est classee umbrella : sa branche n'applique que la sonde de CONTENEUR (has_recent_container_delivery_marker, dernier commentaire). Le gel de l'EPIC n'etait jamais consulte.

Mesure du 2026-11-05 (#19309) : l'EPIC #19309 est gelee par le body (ligne [FROZEN] posee a 17:38Z) et par le fil (depuis le 03/11) ; le tapis l'a servie 7 fois dans la journee -- 7 [RELEASED] sans travail. Un [RELEASED] ne leve pas un gel : c'est la grammaire elle-meme qui l'interdit.

Le correctif

  1. Une sonde de gel a part entiere — has_frozen_marker(issue_number) rend la source du gel ("body" / "comment"), False si l'item n'est pas gele, None si la lecture a echoue. Elle ne lit que le gel : ni le marqueur de livraison de l'item, ni celui de ses enfants. Un parapluie n'herite donc pas de la livraison de ses enfants.
  2. Un gate transversal — la porte est appliquee a toutes les classes (grain, umbrella, delivered), placee avant les filtres de classe et avant le plafond EPIC (Tapis (#18832) : priorite aux issues de consolidation, un sous-grain par visite et plafond hebdomadaire pour les EPICs d'extension #22500). Un candidat gele doit dire « GEL », jamais « PLAFOND EPIC » ni « LIVRAISON », et ne doit pas revenir au tirage suivant.
  3. Une cause nommee — l'ecart sort avec GEL (body|comment) et la regle de degel dans le texte ; la sortie porte un volet dedie (frozen_signal en JSON, ECARTE (gel) en texte).
  4. Un fail-OPEN dit — une lecture ratee laisse le candidat servable, mais le numero est reporte (frozen_unread), comme le fait deja claim_unread / marker_unread.
  5. --admissible branche — le mode repondait « ce grain-ci est-il consommable maintenant ? » et rendait ADMISSIBLE sur un item gele. Le filtre y est branche : il rend REFUS et nomme la cause.

--include-delivered ne contourne pas le gel : cette echappatoire porte sur les marqueurs de livraison, la ou le gel est une decision du coordinateur.

Ce qui ne change pas

  • la grammaire du gel (_issue_is_frozen) : aucune ligne touchee ;
  • le filtre de livraison reste classe : une umbrella n'herite toujours pas de la livraison de ses enfants (c'est la sonde de conteneur, pas la porte de gel) ;
  • les sondes restent injectables et inertes par defaut (doctrine fix(picker,#19907): 3e surface de livraison (PR MERGEE <90j citant #N) #19913) : un test qui n'injecte pas de sonde ne sort jamais sur le reseau.

Cout

Zero requete supplementaire dans le tapis. La lecture du fil est servie par l'instantane de la passe, dont la fenetre couvre exactement celle que la boucle parcourt (wanted = max_iters), et le corps vient de _POOL_BODIES, que fetch_pool remplit deja. La voie ponderee lit une fois de plus par candidat tire (une poignee).

Temoins

scripts/tests/test_pick_idle_grain_freeze_scope.py (15 tests) :

  • temoin 1 — une EPIC gelee par le corps est ecartee du tapis (GEL (body)) ;
  • temoin 2 — une EPIC gelee par le fil est ecartee du tapis (GEL (comment)) ;
  • controle negatif (une EPIC non gelee est servie) ;
  • le gel s'applique a grain, umbrella et delivered ;
  • --include-delivered ne contourne pas le gel ;
  • lecture ratee : fail-OPEN et signalee (frozen_unread) ;
  • la voie ponderee applique la meme porte ;
  • --admissible refuse un item gele.

Validation

  • pytest scripts/tests/test_pick_idle_grain_freeze_scope.py -> 15 passed ;
  • pytest scripts/tests/test_pick_idle_grain.py scripts/tests/test_pick_idle_grain_belt.py scripts/tests/test_pick_frozen_sticky.py scripts/tests/test_pick_delivered_gate.py scripts/tests/test_pick_claim_filter.py -> 498 passed (aucune regression, y compris test_pick_frozen_sticky.py, qui verifie la grammaire du gel et le cache des corps) ;
  • pytest scripts/tests -k "pick or claim or snapshot or candidate_delivered or origami or closure" -> 1943 passed, 2 skipped, 5 xfailed ;
  • pyflakes scripts/pick_idle_grain.py : aucun warning nouveau (les avertissements listes sont anterieurs a ce changement).

Controle de mort (mesure sur l'issue reelle)

Portee

  • scripts/pick_idle_grain.py — la sonde, la porte, le volet de sortie ;
  • scripts/tests/test_pick_idle_grain_freeze_scope.py — les temoins.

PR hors harnais (scripts/) : le merge passe par merge_ready.py apres l'APPROVE du coordinateur, comme annonce au dispatch.

See #19309

🤖 Generated with Claude Code

…C gelee n'est plus servie

Le gel est une decision explicite du coordinateur, portee par deux regles :
regle A (ligne `[FROZEN] ...` dans le CORPS de l'issue) et regle B
(en-tete `[FROZEN]` dans le FIL). `_issue_is_frozen` les lisait deja, mais
elle n'etait cablee que DERRIERE `has_recent_delivery_marker`, lui-meme
cable sur l'urne `grain` SEULE (`draw_unclaimed` : `if cls == "grain" and
not include_delivered`). Une EPIC, classee `umbrella`, n'etait donc jamais
consultee pour son gel.

Mesure du 2026-11-05 (#19309) : l'EPIC est gelee par le body (ligne
`[FROZEN]` depuis 17:38Z) ET par le fil (depuis le 03/11) ; le tapis l'a
servie 7 fois dans la journee -- 7 `[RELEASED]` sans travail.

Le correctif :

- une sonde de gel A PART ENTIERE (`has_frozen_marker`), qui ne lit QUE le
  gel -- ni le marqueur de livraison de l'item, ni celui de ses enfants --
  et rend la SOURCE (`body` / `comment`) ;
- elle est appliquee a TOUTES les classes (`grain`, `umbrella`, `delivered`),
  avant les filtres de classe et avant le plafond EPIC, pour qu'un candidat
  gele dise « GEL » et ne revienne pas au tirage suivant ;
- l'ecart sort avec sa cause (`GEL (body|comment)`) et son propre volet de
  sortie (`frozen_signal` en JSON, `ECARTE (gel)` en texte) ;
- une lecture ratee reste fail-OPEN, mais DITE (`frozen_unread`) ;
- le mode `--admissible` rendait `ADMISSIBLE` sur un item gele : le filtre
  y est branche, et la sortie nomme la cause.

Cout : ZERO requete supplementaire dans le tapis -- la lecture du fil est
servie par l'instantane de la passe, qui couvre la fenetre que la boucle
parcourt, et le corps vient du cache du pool que le pool paie deja. La voie
ponderee lit une fois de plus par candidat tire (une poignee).

Temoins : `scripts/tests/test_pick_idle_grain_freeze_scope.py` -- EPIC gelee
par le corps, EPIC gelee par le fil, controle negatif, gel sur toutes les
classes, `--include-delivered` qui ne contourne pas le gel, lecture ratee
fail-OPEN signalee, voie ponderee, `--admissible`.

Suite : 1943 passed, 2 skipped, 5 xfailed (selection picker/claim/snapshot/
candidate-delivered/origami/closure) ; 498 passed sur la suite du picker.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Avertissements consultatifs

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-ai-01:CoursIA-2` voit ces signaux actifs sur les mergees du jour (UTC 2026-11-05) :

G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

Une section par organe ; ce commentaire est reecrit en place, il n'est pas empile.

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lu le code (scripts/pick_idle_grain.py) et lancé les tests dans un worktree frais à la tête 2ff175c0 : test_pick_idle_grain_freeze_scope.py 15 passed, et 606 passed sur l'ensemble des tests pick_idle.

Ce que j'ai vérifié :

  • la porte de gel se place dans draw_unclaimed AVANT les filtres de classe : elle vaut pour grain, umbrella et delivered, et --include-delivered ne la contourne pas. C'est exactement le défaut de #19309 (une EPIC gelée, de classe umbrella, resservie 7 fois en une journée) ;
  • has_frozen_marker est tri-état : une lecture en échec rend None, en fail-OPEN signalé (frozen_unread), et non un faux « pas gelé » silencieux ;
  • le gel est séparé des marqueurs de livraison : un parapluie n'hérite pas de la livraison de ses enfants ;
  • câblage de production : frozen_probe = has_frozen_marker hors pytest (l.11455-11459), la valeur inerte n'est gardée que sous PYTEST_CURRENT_TEST sans --cache-dir, et la même sonde passe aux deux chemins (l.12156, l.12682) ;
  • --admissible voit aussi le gel (gel_cause_text).

Remarque non bloquante : le texte de cause du gel est écrit deux fois (dans gel_cause_text et en ligne dans draw_unclaimed). On peut le factoriser à la prochaine retouche de ce fichier ; je ne la tiens pas pour une réserve.

B.0 rc=0, mergeable_state clean. APPROVE.

@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #24864 (Fix(picker,#19309): le gel s'applique a toutes les classes -- une EPIC gelee n'est plus servie) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur main. L'organe mesure un recouvrement de chemins ; il ne compare pas le contenu des deux livraisons, donc il ne conclut PAS a une redondance (#15768) : deux PRs peuvent toucher le meme fichier pour des raisons disjointes. L'arbitrage reste a la lane ou au coordinateur.

@myia-ai-01
myia-ai-01 merged commit 7a1966b into main Nov 6, 2026
23 of 25 checks passed
myia-ai-01 pushed a commit that referenced this pull request Nov 6, 2026
…ees (#24919)

La sonde de gel (`has_frozen_marker`) rend `None` sur echec de lecture, et
l'appelant le dit -- fail-OPEN assume, candidat reporte dans
`frozen_unread`. L'etat etait publie dans le JSON (`frozen_signal.unread`),
mais **jamais dit dans un rapport texte** : alors que les cinq lectures
voisines (livraison, couverture, claim, conteneur, marqueur) ont chacune
leur rapport `!! ... NON LU`.

Le gel est un veto **transversal** : il ecarte le candidat de TOUTES les
classes. Un gel non lu laisse donc passer un candidat que le gel aurait
ecarte, et l'operateur qui lit la sortie n'apprendait l'echec que par le
JSON. C'est le meme defaut que #17528 pour les autres sondes.

Ajout : `print_frozen_unread_report`, dans la forme de ses trois pendants
(numero, nature de l'incertitude, ce qu'il faut verifier avant d'editer),
appele sur les deux chemins qui mesurent le gel :

- la boucle de service (`belt_pick_with_replacements`) ;
- le chemin `delivered`, ou la sonde de gel est cablee et produit
  `delivered_state.frozen_unread` -- lui aussi sans rapport texte.

Le fail-OPEN reste assume (le tirage est maintenu) : ce qui n'est pas assume,
c'est le **silence**.

Tests : 3 ajoutes (rendu visible, mut quand rien n'a rate, deduplication des
numeros). Suite complete du picker verte : 200 tests passes
(`test_pick_idle_grain_belt.py`, `test_pick_idle_grain_freeze_scope.py`,
`test_pick_frozen_sticky.py`, `test_pick_claim_filter.py`).

Complement residuel de #24830, closee comme redondante avec #24864 (mergee
sur main le 2026-11-06T02:08:44Z, meme correction du gel, plus complete :
deux points de cablage au lieu d'un, plus le mode --admissible).

See #24516
See #24830

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants